package com.wei.czz.framework.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.dto.admin.UserDto;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.PageQuery;
import com.wei.czz.common.utils.CacheKeyUtils;
import com.wei.czz.common.utils.CopyUtils;
import com.wei.czz.common.utils.RegexUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.vo.admin.userRole.UserRoleFormVo;
import com.wei.czz.common.vo.admin.userRoleGroup.UserRoleGroupFormVo;
import com.wei.czz.framework.admin.service.UserService;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.common.vo.admin.deptUser.DeptUserFormVo;
import com.wei.czz.common.vo.admin.user.UserFormVo;
import com.wei.czz.framework.admin.dao.UserDao;
import com.wei.czz.framework.admin.entity.UserEntity;
import com.wei.czz.framework.common.service.AsyncService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-03-15 10:30:44
 * className: UserServiceImpl 用户操作请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("userService")
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    private final RedisHashHandler redisHashHandler;

    private final AsyncService asyncService;

    @Override
    public void saveOrEdit(UserEntity user) {
        Long userId = user.getUserId();
        if (Objects.isNull(userId)) {

            int count = baseMapper.insert(user);
            log.info("插入用户完成。count={}", count);

            // 操作Redis缓存，增加用户缓存数据
            user.setPassword(null);
            redisHashHandler.put(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), user.getUserId().toString(), user);
        } else {
            String valueKey = userId.toString();
            // 操作Redis缓存，删除用户信息
            redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), valueKey);

            int count = baseMapper.updateById(user);
            log.info("修改用户完成。count={}", count);

            // 异步操作，延时双删缓存
            asyncService.schedule(() -> {
                // 操作Redis缓存，删除用户信息
                redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), valueKey);
            }, 1500, TimeUnit.MILLISECONDS);
        }
    }

    @Transactional
    @Override
    public void batchSave(List<UserEntity> userList) {
        boolean bool = this.saveBatch(userList);
        log.info("批量保存用户完成。bool={}", bool);
    }

    @Override
    public PageDto<UserEntity> getPageList(DeptUserFormVo deptUserFormVo) {
        // 指定排序字段
        deptUserFormVo.setField("u.`" + deptUserFormVo.getField() + "`");

        // 创建mp分页对象
        Page<UserEntity> page = PageQuery.initPage(deptUserFormVo);

        // 分页查询
        baseMapper.selectPageList(page, deptUserFormVo);
        log.info("分页查询用户完成。totalNum={} size={}", page.getTotal(), page.getRecords().size());

        return new PageDto<>(page);
    }

    @Override
    public PageDto<UserEntity> getUserRoleGroupPageList(UserRoleGroupFormVo formVo) {
        formVo.setField("urg.`update_time`");
        formVo.setOrder(Constant.DESCENDING);
        // mp分页对象
        Page<UserEntity> page = PageQuery.initPage(formVo);

        // 分页查询
        page = baseMapper.selectUserRoleGroupPageList(page, formVo);
        log.info("分页查询用户关联角色授权组完成。totalNum={} list.size={}", page.getTotal(), page.getRecords().size());

        return new PageDto<>(page);
    }

    @Override
    public PageDto<UserEntity> getRoleUserPageList(UserRoleFormVo formVo) {
        // mp分页都西昂
        Page<UserEntity> page = PageQuery.initPage(formVo);

        // 分页查询
        page = baseMapper.selectRoleUserPageList(page, formVo);

        return new PageDto<>(page);
    }

    @Override
    public List<UserEntity> findUserList() {
        LambdaQueryWrapper<UserEntity> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配 删除状态 字段
        userLambdaQueryWrapper.eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        // 查询系统用户表，获取用户数据
        List<UserEntity> userList = baseMapper.selectList(userLambdaQueryWrapper);
        log.info("查询所有可用用户完成。size={}", userList.size());
        return userList;
    }

    @Override
    public List<UserEntity> getList(List<Long> userIdList) {
        if (CollectionUtils.isEmpty(userIdList)) {
            log.info("批量获取用户，传入的用户主键列表为空");
            return Collections.emptyList();
        }
        LambdaQueryWrapper<UserEntity> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配 用户主键和删除状态 字段
        userLambdaQueryWrapper.in(UserEntity::getUserId, userIdList)
                .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        // 查询系统用户表，获取用户数据
        List<UserEntity> userList = baseMapper.selectList(userLambdaQueryWrapper);
        log.info("批量查询用户完成。param.size={} list.size={}", userIdList.size(), userList.size());
        return userList;
    }

    @Override
    public List<UserEntity> findUserList(String email, String phone, String loginName) {
        if (StringUtils.isAllBlank(email, phone, loginName)) {
            log.info("获取用户列表，传入的邮箱号、手机号、登陆别名均为空");
            return Collections.emptyList();
        }
        LambdaQueryWrapper<UserEntity> userLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 邮箱号和删除标记（’正常‘） 字段
        userLambdaWrapper.eq(StringUtils.isNotBlank(email), UserEntity::getEmail, email)
                .eq(StringUtils.isNotBlank(phone), UserEntity::getPhone, phone)
                .eq(StringUtils.isNotBlank(loginName), UserEntity::getLoginName, loginName)
                .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        List<UserEntity> userList = baseMapper.selectList(userLambdaWrapper);
        log.info("查询用户完成。phone={} email={} loginName={} size={}", phone, email, loginName, userList.size());
        return userList;
    }

    @Override
    public List<UserDto> getSimpleUserList() {
        LambdaQueryWrapper<UserEntity> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        userLambdaQueryWrapper.select(UserEntity::getUserId, UserEntity::getUsername, UserEntity::getStatus);
        // 匹配条件
        userLambdaQueryWrapper.eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        // 查询数据
        List<UserEntity> userList = baseMapper.selectList(userLambdaQueryWrapper);
        log.info("查询所有可用用户简单数据完成。size={}", userList.size());
        // 列表映射
        return CopyUtils.mapList(userList, user -> {
            UserDto userDto = new UserDto();
            userDto.setUserId(user.getUserId().toString())
                    .setUsername(user.getUsername())
                    .setStatus(user.getStatus())
                    .setStatusName(CommonEnum.ZERO.getValue().equals(user.getStatus()) ? "可用" : "不可用");
            return userDto;
        });
    }

    @Override
    public Map<String, Object> getCacheUserList(UserFormVo userFormVo) {
        // 查询Redis缓存，获取对应类型的所有用户键
        Set<String> userIdSet = redisHashHandler.keys(CacheKeyUtils.getRedisHashKey(EntityConstant.USER));

        // 查询数据库系统用户表，获取用户id列表
        List<String> userIdList = baseMapper.getUserIdList(CommonEnum.ZERO.getValue());

        List<String> residueUserIds = new ArrayList<>(userIdList.size());
        // 数据库存储的数据和缓存数据进行取交集操作
        for (String userId : userIdList) {
            if (userFormVo.getCacheStatus()) {
                if (userIdSet.contains(userId)) {
                    residueUserIds.add(userId);
                }
            } else {
                if (!userIdSet.contains(userId)) {
                    residueUserIds.add(userId);
                }
            }
        }
        List<UserDto> userDtoList = new ArrayList<>(userFormVo.getLimit());
        long size = 0;
        if (!residueUserIds.isEmpty()) {

            LambdaQueryWrapper<UserEntity> userLambdaWrapper = new LambdaQueryWrapper<>();
            // 查询 用户id、用户名称、手机号、邮箱号、登录别名和创建时间 字段
            userLambdaWrapper.select(UserEntity::getUserId, UserEntity::getUsername, UserEntity::getPhone, UserEntity::getEmail,
                    UserEntity::getLoginName, UserEntity::getCreateTime);
            // 匹配 用户id（是）、用户名称（检索值不为空时）和登录别名用户名称（检索值不为空时） 字段
            userLambdaWrapper.in(UserEntity::getUserId, residueUserIds)
                    .eq(StringUtils.isNotBlank(userFormVo.getWord()), UserEntity::getUsername, userFormVo.getWord())
                    .eq(StringUtils.isNotBlank(userFormVo.getLoginName()), UserEntity::getLoginName, userFormVo.getLoginName());
            if (StringUtils.isNotBlank(userFormVo.getContact())) {
                // 正则判断检索类型用户登录账号
                if (RegexUtils.isPhone(userFormVo.getContact())) {
                    /*
                        正则判断结果是手机号
                     */
                    // 匹配 手机号 字段
                    userLambdaWrapper.eq(UserEntity::getPhone, userFormVo.getContact());
                } else if (RegexUtils.isEmail(userFormVo.getContact())) {
                    /*
                        正则判断结果是邮箱号
                     */
                    // 匹配 邮箱号 字段
                    userLambdaWrapper.eq(UserEntity::getEmail, userFormVo.getContact());
                } else {
                    throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "请输入正确的手机号或者邮箱号进行检索");
                }
            }
            // 构造mp分页对象
            Page<UserEntity> page = PageQuery.initPage(userFormVo);
            // 查询数据库系统用户表，分页查询用户信息列表
            this.page(page, userLambdaWrapper);

            size = page.getTotal();

            for (UserEntity user : page.getRecords()) {
                UserDto userDto = new UserDto();
                // 设置用户id、用户名称、手机号、邮箱号、登录别名、用户类型和创建时间属性值
                userDto.setUserId(user.getUserId().toString())
                        .setUsername(user.getUsername())
                        .setPhone(user.getPhone())
                        .setEmail(user.getEmail())
                        .setLoginName(user.getLoginName())
                        .setCreateTime(user.getCreateTime());

                userDtoList.add(userDto);
            }
        }
        Map<String, Object> result = new HashMap<>();
        result.put("cacheUserSize", size);
        result.put("page", new PageDto<>(userDtoList, size, userFormVo.getPage(), userFormVo.getLimit()));

        return result;
    }

    @Override
    public UserEntity get(Long userId) {
        // 查询数据库系统用户表，根据用户id获取用户信息
        UserEntity user = baseMapper.selectById(userId);
        if (Objects.isNull(user)) {
            log.info("用户不存在。userId={}", userId);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户不存在，请确认");
        }
        if (CommonEnum.ONE.getValue().equals(user.getDeleteStatus())) {
            log.info("用户已删除。userId={}", userId);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户不存在，请确认");
        }
        return user;
    }

    @Override
    public Map<String, Object> getUserCacheInfo(Long userId) {

        // 查询Redis，获取用户信息
        UserEntity user = redisHashHandler.get(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), userId.toString());
        if (user == null) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(),
                    "您查询的用户缓存信息不存在，请确认，如有问题，请联系管理员处理。");
        }
        Map<String, Object> result = new HashMap<>(8);
        result.put("structKey", CacheKeyUtils.getRedisHashKey(EntityConstant.USER));
        result.put("valueKey", userId.toString());
        result.put("data", user);
        return result;
    }

    @Override
    public <R> Map<R, String> getNameMap(Collection<Long> userIdCollection, @NonNull Function<Long, R> function) {
        if (CollectionUtils.isEmpty(userIdCollection)) {
            log.info("用户主键集合为空");
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<UserEntity> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询用户id和用户姓名字段
        userLambdaQueryWrapper.select(UserEntity::getUserId, UserEntity::getUsername);
        // 匹配 用户id 字段
        userLambdaQueryWrapper.in(UserEntity::getUserId, userIdCollection);
        // 查询数据库系统用户表，获取用户数据列表
        List<UserEntity> userList = baseMapper.selectList(userLambdaQueryWrapper);
        // List 转 Map
        return userList.stream().collect(Collectors.toMap(
                user -> function.apply(user.getUserId()),
                UserEntity::getUsername)
        );
    }

    @Override
    public Long getUserCount() {
        LambdaQueryWrapper<UserEntity> userLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 删除状态 字段
        userLambdaWrapper.eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        Long count = baseMapper.selectCount(userLambdaWrapper);
        log.info("查询系统用户数量完成。count={}", count);
        return count;
    }

    @Override
    public <R> List<NameValue<R>> findUserList(Set<Long> userIdSet, @NonNull Function<Long, R> function) {
        LambdaQueryWrapper<UserEntity> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        userLambdaQueryWrapper.select(UserEntity::getUserId, UserEntity::getUsername);
        // 匹配条件
        userLambdaQueryWrapper.in(UserEntity::getUserId, userIdSet)
                .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        // 查询
        List<UserEntity> userList = baseMapper.selectList(userLambdaQueryWrapper);
        if (userList.isEmpty()) {
            log.info("用户列表为空。userIdSet={}", userIdSet);
            return Collections.emptyList();
        }

        return userList.stream()
                .map(user -> {
                    Long userId = user.getUserId();
                    R value = function.apply(userId);
                    return new NameValue<>(user.getUsername(), value);
                })
                .collect(Collectors.toList());
    }

    @Override
    public void checkLoginInfo(Long userId, String phone, String email, String loginName) {
        LambdaQueryWrapper<UserEntity> userLambdaWrapper;
        // 手机号校验
        if (StringUtils.isNotBlank(phone)) {
            userLambdaWrapper = new LambdaQueryWrapper<>();
            // 匹配 手机号、用户id（非必须）和删除标记 字段
            userLambdaWrapper.eq(UserEntity::getPhone, phone)
                    .ne(Objects.nonNull(userId), UserEntity::getUserId, userId)
                    .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
            // 查询数据库用户信息表，判断‘用户登录手机号’是否存在
            long count = baseMapper.selectCount(userLambdaWrapper);
            log.info("用户登录手机号判重完成。count={}", count);
            if (count > 0) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户登录手机号已经存在，如有问题，请联系管理员!");
            }
        }
        // 邮箱号校验
        if (StringUtils.isNotEmpty(email)) {
            userLambdaWrapper = new LambdaQueryWrapper<>();
            // 匹配 邮箱号、用户id（非必须）和删除标记 字段
            userLambdaWrapper.eq(UserEntity::getEmail, email)
                    .ne(Objects.nonNull(userId), UserEntity::getUserId, userId)
                    .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
            // 查询数据库用户信息表，判断‘用户登录邮箱号’是否存在
            long count = baseMapper.selectCount(userLambdaWrapper);
            log.info("用户登录邮箱号判重完成。count={}", count);
            if (count > 0) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户登录邮箱号已经存在，如有问题，请联系管理员!");
            }
        }
        // 登录别名校验
        if (StringUtils.isNotEmpty(loginName)) {
            userLambdaWrapper = new LambdaQueryWrapper<>();
            // 匹配 登录别名、用户id（非必须）和删除标记 字段
            userLambdaWrapper.eq(UserEntity::getLoginName, loginName)
                    .ne(Objects.nonNull(userId), UserEntity::getUserId, userId)
                    .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
            // 查询数据库用户信息表，判断‘用户登录别名’是否存在
            long count = baseMapper.selectCount(userLambdaWrapper);
            log.info("用户登录别名判重完成。count={}", count);
            if (count > 0) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户登录别名已经存在，请重新输入!");
            }
        }
    }

    @Override
    public void updatePassword(Long userId, String password) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        UserEntity updateUser = new UserEntity();
        updateUser.setUserId(userId)
                .setPassword(password)
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());
        // 修改
        int count = baseMapper.updateById(updateUser);
        log.info("修改用户密码完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户不存在，修改密码失败");
        }
    }

    @Transactional
    @Override
    public void batchUpdate(List<UserEntity> userList) {
        // 操作系统用户表，批量更新用户数据
        boolean bool = this.updateBatchById(userList);
        log.info("批量更新用户完成：bool={}", bool);
    }

    @Override
    public void delete(List<Long> userIdList) {
        // 获取正在删除用户的用户id
        Long optUserId = SecurityUtils.getUserId();
        Date date = new Date();

        LambdaUpdateWrapper<UserEntity> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置 删除标记、更新时间和操作更新的用户id 字段值
        userLambdaUpdateWrapper.set(UserEntity::getDeleteStatus, CommonEnum.ONE.getValue())
                .set(UserEntity::getUpdateTime, date)
                .set(UserEntity::getUpdateUserId, optUserId);
        // 匹配 用户主键（列表） 字段
        userLambdaUpdateWrapper.in(UserEntity::getUserId, userIdList)
                .eq(UserEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        // 操作数据库系统用户表，批量删除用户
        int count = baseMapper.update(userLambdaUpdateWrapper);
        log.info("删除用户完成。count={}", count);
    }

}